package robotlion.model;

import robotlion.controller.InfoRobot;
import robotlion.view.Observateur;
import java.awt.Point;
import java.util.ArrayList;
import javax.swing.tree.DefaultMutableTreeNode;
import robotlion.pathfinding.PathfindingDijkstra;

/**
 *
 * @author Adrien Dos Reis
 */
public class Robot extends Observable{
    private InfoRobot infoPublic;
    private String nom;
    private int vitesse;
    private Point position;
    private Point destination;
    private int nivAccessibilite;
    private EEtat etat;
    private int algorithme;
    
    private int distanceParcourue;
    
    private ArrayList<Point> cheminASuivre;
    private ArrayList<Observateur> listObservateur;
    
    public Robot(String p_nom, int p_vitesse, Point p_position, int p_nivAccessibilite, int p_algorithme)
    {
       nom = p_nom;
       vitesse = p_vitesse;
       position = p_position;
       nivAccessibilite = p_nivAccessibilite;
       algorithme = p_algorithme;
       etat = EEtat.Libre;
       cheminASuivre = new ArrayList<Point>();
       listObservateur = new ArrayList<Observateur>();
       infoPublic = new InfoRobot();
    }
    
    public void seDeplacer(Carte map)
    {
        // Si le robot n'a pas atteint sa destination
        if (destination != null && cheminASuivre != null)
        {
            if (!this.position.equals(this.destination))
            {
                etat = EEtat.SeDeplace;
                // Alors on consulte le tableau indiquant au robot où se trouve la 
                // prochaine coordonnée à explorer, et on le déplace vers cette coordonnée
                // On supprime également cette coordonnée du tableau (soucis d'optimisation
                // de la taille du tableau)
                Point ouAller = this.cheminASuivre.remove(0);

                this.position.x=ouAller.x;
                this.position.y=ouAller.y;
            }
            else
            {
                eteindreFeu(map);
            }
            updateObservateur(null); 
        }

    }

    public Point getPosition() {
        return position;
    }

    public Point getDestination() {
        return destination;
    }
    
    public void eteindreFeu(Carte map)
    {
        if (!map.isIncendie(position.x, position.y))
        {
            etat = EEtat.Libre;
            destination = null;
            cheminASuivre = null;
            System.out.println("Feu éteint");
        }
        else
        {
            etat = EEtat.EteindUnIncendie;
            System.out.println("Je l'éteins");
            map.decrIncendie(position.x, position.y, 1);
        }
    }
    
    public void calculItineraire()
    {
 
    }
    
    public int repondreObjectif(Carte carte, Point objectif)
    {
        /*int calculTrajet=0;
        calculTrajet += Math.abs(position.x - objectif.x);
        calculTrajet += Math.abs(position.y - objectif.y);
        calculTrajet = calculTrajet / vitesse;
        return calculTrajet;*/
        
        // Instanciation de l'algorithme de pathfinding
        PathfindingDijkstra pathfinding = new PathfindingDijkstra(carte);
        
        System.out.println("Objectif : ("+objectif.x+"; "+objectif.y+")");
        
        // La méthode dijkstra retourne un objet de la classe DefaultMutableTreeNode,
        // contenant les coordonnées du point final, et permettant de remonter
        // tout le chemin parcouru pour arriver à ce point
        DefaultMutableTreeNode noeudFinal = pathfinding.dijkstra(new DefaultMutableTreeNode(this.position), objectif, this.nivAccessibilite, 0, true);
        
        this.cheminASuivre = pathfinding.recupererPlusCourtChemin(noeudFinal);
        
        // On renvoie au manager le "coût" du déplacement jusqu'à l'objectif
        return pathfinding.getLastPoidsCumule();
    }
    
    public void prendreObjectif(Point objectif)
    {
        etat = EEtat.SeDeplace;
        destination=objectif;
    }
    
    public int getAlgorithme() {
        return algorithme;
    }

    public void setAlgorithme(int algorithme) {
        this.algorithme = algorithme;
    }

    public ArrayList<Point> getCheminASuivre() {
        return cheminASuivre;
    }

    public void setCheminASuivre(ArrayList<Point> cheminASuivre) {
        this.cheminASuivre = cheminASuivre;
    }

    public EEtat getEtat() {
        return etat ;
    }

//    public void setEstLibre(boolean estLibre) {
//        this.estLibre = estLibre;
//    }

    public int getNivAccessibilite() {
        return nivAccessibilite;
    }

    public void setNivAccessibilite(int nivAccessibilite) {
        this.nivAccessibilite = nivAccessibilite;
    }

    public String getNom() {
        return nom;
    }

    public void setNom(String nom) {
        this.nom = nom;
    }

    public int getVitesse() {
        return vitesse;
    }

    public void setVitesse(int vitesse) {
        this.vitesse = vitesse;
    }
    
    private InfoRobot getInfoPublic()
    {
        this.infoPublic.algorithme= this.algorithme;
        this.infoPublic.destination= this.destination;
        this.infoPublic.etat= this.etat;
        this.infoPublic.nivAccessibilite= this.nivAccessibilite;
        this.infoPublic.nom= this.nom;
        this.infoPublic.position= this.position;
        this.infoPublic.vitesse= this.vitesse;
        return this.infoPublic;
    }
    
    /**
     * Ajoute un observateur à la liste
     */
    public void addObservateur(Observateur obs) {
        this.listObservateur.add(obs);
        obs.updateObs(getInfoPublic());
    }
    
    /**
     * Retire tous les observateurs de la liste
     */
    public void delObservateur() {
        for(Observateur obs : this.listObservateur)
                obs.updateObs(this.nom);
        this.listObservateur = new ArrayList<Observateur>();
    }
    
    /**
     * Avertit les observateurs que l'observable a changé 
     * et invoque la méthode update de chaque observateur !
     */
    public void updateObservateur(Object info) {          
        for(Observateur obs : this.listObservateur)
                obs.updateObs(getInfoPublic());
    }

    
}
